﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

//buddy
using Zeta;
using Zeta.Common;
using Zeta.CommonBot;
using Zeta.Common.Plugins;
using Zeta.Internals;
using Zeta.Internals.Actors;
using Zeta.Internals.Service;

using BossHog.ProfileBuilder;

namespace BossHog
{
    public partial class ProfileEditor : UserControl
    {

        public ProfileEditor()
        {
            InitializeComponent();
            NewProfile();
        }

        private string filePath = "";

        bool IsValidXml(string xml)
        {
            bool ret = true;
            lock (this)
            {
                System.Xml.XmlTextReader r = null;
                System.IO.StringReader sr = null;
                try
                {
                    sr = new System.IO.StringReader(xml);
                    r = new System.Xml.XmlTextReader(sr);
                    while (r.Read()) { }
                }
                catch (Exception ex)
                {
                    Logging.Write("[BossHog] Error: " + ex.Message);
                    ret = false;
                }
                finally
                {
                    if (null != r)
                    {
                        r.Close();
                        r = null;
                    }

                    if (null != sr)
                    {
                        sr.Close();
                        sr = null;
                    }
                }
            }
            return ret;
        }

        void NewProfile()
        {
            filePath = "";
            profileXmlTxt.Text = "<Profile>\r\n\t<Name>New Profile</Name>\r\n\t<GameParams />\r\n\t<Order>\r\n\t\t<!-- new instructions here -->\r\n\t</Order>\r\n</Profile>";
            profileXmlTxt.FormatXml();
        }

        void AddOrder(IOrderChildElement t)
        {
            string ts = t.ToString();
            int ti = profileXmlTxt.SelectionStart;
            string tmp = profileXmlTxt.Text;

            profileXmlTxt.Text = tmp.Insert(ti, ts);

            ti += ts.Length;
            profileXmlTxt.FormatXml();
            profileXmlTxt.RestoreCaret(ti);
        }

        void Open()
        {
            System.IO.Stream s = null;
            System.IO.StreamReader sr = null;

            try
            {
                s = System.IO.File.Open(filePath, System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite, System.IO.FileShare.Read);
                sr = new System.IO.StreamReader(s);
                string xml = sr.ReadToEnd();
                profileXmlTxt.Text = xml;
                profileXmlTxt.FormatXml();
            }
            catch (Exception ex)
            {
                Logging.Write("[BossHog] Error: " + ex.Message);
            }
            finally
            {
                if (null != sr)
                {
                    sr.Close();
                    sr.Dispose();
                    sr = null;
                }

                if (null != s)
                {
                    s.Close();
                    s.Dispose();
                    s = null;
                }
            }
        }

        void Save()
        {
            System.IO.Stream s = null;
            System.IO.StreamWriter w = null;

            try
            {
                try
                {
                    if (System.IO.File.Exists(filePath))
                    {
                        System.IO.File.Delete(filePath);
                    }
                }
                catch (Exception failed) { Logging.Write(LogLevel.Verbose, "[BossHog] Error: " + failed.Message); }

                s = System.IO.File.Open(filePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.Read);
                w = new System.IO.StreamWriter(s);
                lock (this)
                {
                    w.Write(profileXmlTxt.Text);
                }

            }
            catch (Exception ex)
            {
                Logging.Write("[BossHog] Error: " + ex.Message);
            }
            finally
            {
                if (null != w)
                {
                    w.Close();
                    w.Dispose();
                    w = null;
                }

                if (null != s)
                {
                    s.Close();
                    s.Dispose();
                    s = null;
                }
            }
        }
        void SaveAs()
        {
            string fp = "";
            DialogResult r = saveProfileDlg.ShowDialog();
            if (r == System.Windows.Forms.DialogResult.OK)
            {
                fp = saveProfileDlg.FileName;
                System.IO.Stream s = null;
                System.IO.StreamWriter w = null;
                try
                {
                    if (System.IO.File.Exists(fp))
                    {
                        System.IO.File.Delete(fp);
                    }
                }
                catch (Exception failed) { Logging.Write(LogLevel.Verbose, "[BossHog] Error: " + failed.Message); }

                try
                {
                    s = System.IO.File.Open(fp, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.Read);
                    w = new System.IO.StreamWriter(s);
                    lock (this)
                    {
                        w.Write(profileXmlTxt.Text);
                    }
                    filePath = fp;
                }
                catch (Exception ex)
                {
                    Logging.Write("[BossHog] Error: " + ex.Message);
                }
                finally
                {
                    if (null != w)
                    {
                        w.Close();
                        w.Dispose();
                        w = null;
                    }

                    if (null != s)
                    {
                        s.Close();
                        s.Dispose();
                        s = null;
                    }
                }
            }
        }

        void Run()
        {
            BotMain.Stop();
            string fp = filePath;
            filePath = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments) + "\\BWTmp.xml";
            Save();
            Zeta.CommonBot.ProfileManager.Load(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments) + "\\BWTmp.xml");
            filePath = fp;
            BotMain.Start();
        }

        #region Order Menu
        private void useTownPortalClick(object sender, EventArgs e)
        {
            AddOrder(new UseTownPortalElement());
        }

        private void useObjectToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            AddOrder(new UseObjectElement());
        }

        private void talkToClick(object sender, EventArgs e)
        {
            AddOrder(new TalkToElement());
        }

        private void usePowerClick(object sender, EventArgs e)
        {
            AddOrder( new UsePowerElement());
        }

        private void useWaypointToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddOrder( new UseWaypointElement());
        }

        private void moveToClick(object sender, EventArgs e)
        {
            AddOrder( new MoveToElement());
        }

        private void waitClick(object sender, EventArgs e)
        {
            AddOrder( new WaitTimerElement());
        }

        private void skipCutsceneClick(object sender, EventArgs e)
        {
            AddOrder( new SkipCutsceneElement());
        }

        private void leaveGameClick(object sender, EventArgs e)
        {
            AddOrder( new LeaveGameElement());
        }

        private void writeReportClick(object sender, EventArgs e)
        {
            AddOrder(new WriteReportElement());
        }

        private void ifClick(object sender, EventArgs e)
        {
            AddOrder( new IfElement());
        }

        private void whileClick(object sender, EventArgs e)
        {
            AddOrder( new WhileElement());
        }

        #endregion
        #region Misc Events
        private void saveProfileBtn_Click(object sender, EventArgs e)
        {
            if (filePath == "")
            {
                DialogResult r = saveProfileDlg.ShowDialog();
                if (r == System.Windows.Forms.DialogResult.OK)
                {
                    filePath = saveProfileDlg.FileName;
                    Save();
                }
            }
            else
            {
                Save();
            }
        }
        private void openProfileBtn_Click(object sender, EventArgs e)
        {
            DialogResult r = openProfileDlg.ShowDialog();
            if (r == System.Windows.Forms.DialogResult.OK)
            {
                if (System.IO.File.Exists(openProfileDlg.FileName))
                {
                    filePath = openProfileDlg.FileName;
                    Open();
                }
            }
        }

        private void newProfileBtn_Click(object sender, EventArgs e)
        {
            NewProfile();
        }

        #endregion
        #region UseObject Menus
        void BindUseObjectMenus()
        {
            lock (this)
            {
                useObjectToolStripMenuItem1.DropDownItems.Clear();
                talkToToolStripMenuItem.DropDownItems.Clear();
                useWaypointToolStripMenuItem.DropDownItems.Clear();

                IEnumerable<ACD> acds = ZetaDia.Actors.GetActorsOfType<ACD>();
                IEnumerator<ACD> ieAcd = acds.GetEnumerator();

                while (ieAcd.MoveNext())
                {
                    try { AddUseWpMenuItem(ieAcd.Current); }
                    catch (Exception ex) { Logging.Write(LogLevel.Verbose, "[BossHog] Error: " + ex.Message); }
                    try { AddTalkToMenuItem(ieAcd.Current); }
                    catch (Exception ex) { Logging.Write(LogLevel.Verbose, "[BossHog] Error: " + ex.Message); }
                    try { AddObjectMenuItem(ieAcd.Current); }
                    catch (Exception ex) { Logging.Write(LogLevel.Verbose, "[BossHog] Error: " + ex.Message); }
                }

                SortOptions(useObjectToolStripMenuItem1.DropDownItems);
                SortOptions(talkToToolStripMenuItem.DropDownItems);
                SortOptions(useWaypointToolStripMenuItem.DropDownItems);
            }
        }

        void SortOptions(ToolStripItemCollection options)
        {
            System.Collections.ArrayList items = new System.Collections.ArrayList(options);
            items.Sort(new ToolstripItemComparer());
            options.Clear();
            for (int i = 0; i < items.Count; i++)
            {
                options.Add((ToolStripItem)items[i]);
            }
        }

        public class ToolstripItemComparer : System.Collections.IComparer
        {
            public ToolstripItemComparer() { }
            public int Compare(object x, object y)
            {
                if (!(x is ToolStripItem && y is ToolStripItem))
                {
                    throw new InvalidOperationException();
                }

                return string.Compare(((ToolStripItem)x).Text, ((ToolStripItem)y).Text);
            }
        }

        void AddObjectMenuItem(ACD acd)
        {
            if (acd.ActorType == Zeta.Internals.SNO.ActorType.Gizmo || acd.ActorType == Zeta.Internals.SNO.ActorType.AxeSymbol || acd.ActorType == Zeta.Internals.SNO.ActorType.ServerProp)
            {
                ToolStripMenuItem item = new ToolStripMenuItem();
                item.Text = acd.Name + ":" + acd.ActorSNO.ToString();
                item.Click += new EventHandler(objectItem_Click);
                item.Tag = acd;
                item.ToolTipText = acd.Name + " is a " + acd.ActorType.ToString() + " at " + acd.Position.ToString();
                useObjectToolStripMenuItem1.DropDownItems.Add(item);
            }
        }

        void AddTalkToMenuItem(ACD acd)
        {
            if (acd.ActorType == Zeta.Internals.SNO.ActorType.Unit)
            {
                ToolStripMenuItem item = new ToolStripMenuItem();
                item.Text = acd.Name + ":" + acd.ActorSNO.ToString();
                item.Click += new EventHandler(talkToItem_Click);
                item.Tag = acd;
                item.ToolTipText = acd.Name + " is a " + acd.ActorType.ToString() + " at " + acd.Position.ToString();
                talkToToolStripMenuItem.DropDownItems.Add(item);
            }
        }

        void AddUseWpMenuItem(ACD acd)
        {
            if(acd.Name.ToLower().Contains("waypoint"))
            {
                ToolStripMenuItem item = new ToolStripMenuItem();
                item.Text = acd.Name + ":" + acd.ActorSNO.ToString();
                item.Click += new EventHandler(useWpItem_Click);
                item.Tag = acd;
                item.ToolTipText = acd.Name + " is a " + acd.ActorType.ToString() + " at " + acd.Position.ToString();
                useWaypointToolStripMenuItem.DropDownItems.Add(item);
            }
        }

        void objectItem_Click(object sender, EventArgs e)
        {
            UseObjectElement p = new UseObjectElement();
            ACD acd = (ACD)((ToolStripMenuItem)sender).Tag;
            p.questId = ZetaDia.CurrentQuest.QuestSNO.ToString();
            p.actorId = acd.ActorSNO.ToString();
            p.x = acd.Position.X.ToString();
            p.y = acd.Position.Y.ToString();
            p.z = acd.Position.Z.ToString();
            p.isPortal = "False";
            p.destinationWorldId = "-1";
            AddOrder(p);
        }

        void talkToItem_Click(object sender, EventArgs e)
        {
            TalkToElement p = new TalkToElement();
            ACD acd = (ACD)((ToolStripMenuItem)sender).Tag;
            p.questId = ZetaDia.CurrentQuest.QuestSNO.ToString();
            p.actorId = acd.ActorSNO.ToString();
            p.x = acd.Position.X.ToString();
            p.y = acd.Position.Y.ToString();
            p.z = acd.Position.Z.ToString();
            p.stepId = ZetaDia.CurrentQuest.StepId.ToString();
            AddOrder(p);
        }

        void useWpItem_Click(object sender, EventArgs e)
        {
            UseWaypointElement p = new UseWaypointElement();
            ACD acd = (ACD)((ToolStripMenuItem)sender).Tag;
            p.questId = ZetaDia.CurrentQuest.QuestSNO.ToString();
            p.actorId = acd.ActorSNO.ToString();
            p.x = acd.Position.X.ToString();
            p.y = acd.Position.Y.ToString();
            p.z = acd.Position.Z.ToString();
            p.waypointNumber = "-1";
            AddOrder(p);
        }
        #endregion

        private void useObjectToolStripMenuItem_MouseHover(object sender, EventArgs e)
        {
            BindUseObjectMenus();
        }

        private void profileXmlTxt_KeyUp(object sender, KeyEventArgs e)
        {
            profileXmlTxt.SaveCaret();
            profileXmlTxt.FormatXml();
            profileXmlTxt.RestoreCaret();
        }

        private void ProfileEditor_SizeChanged(object sender, EventArgs e)
        {

        }

        private void saveProfileAsBtn_Click(object sender, EventArgs e)
        {
            SaveAs();
        }

        public override string Text { get { return profileXmlTxt.Text; } set { profileXmlTxt.Text = value; } }


        public void FormatXml()
        {
            profileXmlTxt.SaveCaret();
            profileXmlTxt.FormatXml();
            profileXmlTxt.RestoreCaret();
        }
    }
}
